   
local storage    = require "resty.gcsdfs.storage"              --加载storage �?
local vss_method = require "gcs.list.method"
local utils      = require "gcs.utils"
local http        = require "resty.http"
local str_len  = string.len
local str_gsub = string.gsub
local tonumber = tonumber
local pairs    = pairs
local cjson    = require "cjson"
local math     = math
local tb_insert= table.insert
local table = table
local ngx      = ngx
local string   = string
local tb_remove= table.remove
local tostring = tostring
local str_sub  = string.sub
local str_find = string.find
local os  = os
--local lo_ip = "128.127.110.189"
local math_floor = math.floor
local config_table             = ngx.shared.gcs_config
local gfile_url                = config_table:get("p_gfile_url")
local cjson_queue              = config_table:get("d_queue")  --加载队列 table
local store_connect_timeout    = config_table:get("p_store_connect_timeout")         --加载storage连接时间
local store_keep_timeout       = config_table:get("p_store_keep_timeout")            --加载storage超时时间
local store_keep_count         = config_table:get("p_store_keep_count")
local send_url        = config_table:get("p_send_url")
-------1定义公共组件（结束）----------------
module(...)
local version = '0.1'


---------------------------------------------
----开�?---


function get_version()
  return version
end


local function StringSplit(string,split)
  local list = {}
  local pos = 1
  if string.find("", split, 1) then -- this would result in endless loops
    return nil,"split matches empty string!"
  end
  while 1 do
    local first, last = string.find(string, split, pos)
    if first then -- found?
      table.insert(list, string.sub(string, pos, first-1))
      pos = last+1
    else
      table.insert(list, string.sub(string, pos))
      break
    end
  end
  return list
end


local function format_time(time)
  --2014-09-15 17:20:00 000
  local t_time = {}
  t_time[1] = string.sub(time,1,4)
  t_time[2] = "-"
  t_time[3] = string.sub(time,5,6)
  t_time[4] = "-"
  t_time[5] = string.sub(time,7,8)
  t_time[6] = " "
  t_time[7] = string.sub(time,9,10)
  t_time[8] = ":"
  t_time[9] = string.sub(time,11,12)
  t_time[10] = ":"
  t_time[11] = string.sub(time,13,14)
  t_time[12] = " "
  t_time[13] = string.sub(time,15,17)
  return table.concat(t_time)
end

local function webservice(host,port,body)
  local res = {}
  local hc = http:new()
  local url = "http://" ..host ..":" ..send_url
  utils.gcs_log("debug","发送ip地址为" ..cjson.encode(url))
  res.ok, res.code, res.headers, res.status, res.body  = hc:request {
    url = url,
    timeout = 5000,
    method = "POST", -- POST or GET
    -- add post content-type and cookie
    headers = {["Content-Type"] = "application/soap+xml; charset=utf-8" },
    body = body
  }
  utils.gcs_log("debug","返回结果" ..cjson.encode(res))
  if not res.ok then
    utils.gcs_log("debug","返回结果" ..url)
    return nil,"webservice is err,url:"..url
  end
  return res,nil
end

local function down_storage(storage_res,tb_value,gfile)
  local str_gfile
  local arg = tb_value
  local st = storage:new()
  st:set_timeout(arg.timeout)
  local ok, err = st:connect(storage_res)
  if not ok then
    return nil,err,1100                             --错误码待定义
  end
  str_gfile,err = st:download_file_to_buff1(gfile)
  if not str_gfile then
    return nil,err,1008
  end

  --关闭storage
  local ok, err = st:set_keepalive(arg.keep_timeout,arg.keep_count)
  return str_gfile
end





---转义数据
local function change_data(data)
  --cd,clpp,clzt,csys,道路编码,地点编码,xsfx,hpys,号牌种类,卡口编号,设备抓拍方向
  local tb_csys = {}
  tb_csys["未知颜色"]= 99
  tb_csys["白色"]= 1
  tb_csys["灰色"]= 2
  tb_csys["黑色"]= 10
  tb_csys["红色"]= 5
  tb_csys["蓝色"]= 8
  tb_csys["黄色"]= 3
  tb_csys["绿色"]= 7
  tb_csys["棕色"]= 9
  tb_csys["粉色"]= 4
  tb_csys["紫色"]= 6
  local tb_xsfx = {}
  tb_xsfx["N"] = 1
  tb_xsfx["W"] = 2
  tb_xsfx["S"] = 3
  tb_xsfx["E"] = 4
  local tb_chdata = {}

  tb_chdata.time = format_time(data.time1)
  tb_chdata.clzt = 1
  if data.hphm == "无车牌" then
    data.hphm = "无牌"
  end
  tb_chdata.hphm = data.hphm
  tb_chdata.hpzl = data.hpzl
  tb_chdata.xssd = data.xssd
  tb_chdata.hpys = data.cllk
  tb_chdata.sbbh = data.sbbh
  tb_chdata.cdbm = data.cd
  tb_chdata.xsfx = tb_xsfx[data.xsfx]
  if data.lx == "dj" then
    tb_chdata.zpfx = 2         --抓车头
  else
    tb_chdata.zpfx = 1
  end
  tb_chdata.csys = tb_csys[data.csys] or 99
  tb_chdata.clpp = "99"
  tb_chdata.lkbh = data.lkbh
  utils.gcs_log("debug","路口编号"..data.lkbh)
  tb_chdata.hpsztpzb = data.hpsztpzb
  tb_chdata.jszb = "0,0,0,0"      --驾驶坐标
  local tb_value = {
    timeout = store_connect_timeout,
    keep_timeout = store_keep_timeout,
    keep_count = store_keep_count
  }
  
  local tb_gfile = {}
  if not data.str_res1 then
      utils.gcs_log("error","没有str_res1")
    else
     local gfile1,err = down_storage(cjson.decode(data.str_res1),tb_value,data.gfile1)
     if not gfile1 then
      return nil,err,1100
     end
     tb_gfile.gfile1 = gfile1
  end
    if data.str_res2 then
      local gfile2,err = down_storage(cjson.decode(data.str_res2),tb_value,data.gfile2)
      if not gfile2 then
        return nil,err,1101
      end
      tb_gfile.gfile2 = gfile2
      else
      tb_gfile.gfile2 = ""
    end
  
    
  tb_chdata.gfile1 = ngx.encode_base64(tb_gfile.gfile1)
  tb_chdata.gfile2 = ngx.encode_base64(tb_gfile.gfile2)
  return tb_chdata,nil,nil
end



local function check_body(body)
  local code = ""
  
  local i,j = string.find(body,"<ns1:out>")
  local k,l = string.find(body,"</ns1:out>")
  local message = string.sub(body,j+1,k-1)
  if message == "OK" or string.find(message,"drop") then
    code = 0
  else
    code = -2
  end
  return code,message
end





local function load_ws_xml(ch_list_data)
  local tb_xml = {}
  tb_xml[1] = [[
      <soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/" 
      xmlns:xsd="http://www.w3.org/2001/XMLSchema" 
      xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
      <soap:Body><ns1:SetPassCarInfo_withImg xmlns:ns1="http://DefaultNamespace">
      <ns1:in0>]]..ch_list_data.time
  tb_xml[2] = [[</ns1:in0><ns1:in1>]]..ch_list_data.clzt
  tb_xml[3] = [[</ns1:in1><ns1:in2>]]..ch_list_data.hphm
  tb_xml[4] = [[</ns1:in2><ns1:in3>]]..ch_list_data.hpzl
  tb_xml[5] = [[</ns1:in3><ns1:in4>]]..ch_list_data.xssd
  tb_xml[6] = [[</ns1:in4><ns1:in5>]]..ch_list_data.hpys
  tb_xml[7] = [[</ns1:in5><ns1:in6>]]..ch_list_data.sbbh
  tb_xml[8] = [[</ns1:in6><ns1:in7>]]..ch_list_data.cdbm
  tb_xml[9] = [[</ns1:in7><ns1:in8>]]..ch_list_data.xsfx
  tb_xml[10] = [[</ns1:in8><ns1:in9>]]..ch_list_data.zpfx
  tb_xml[11] = [[</ns1:in9><ns1:in10>]]..ch_list_data.csys
  tb_xml[12] = [[</ns1:in10><ns1:in11>]]..ch_list_data.clpp
  tb_xml[13] = [[</ns1:in11><ns1:in12>]]..ch_list_data.lkbh         --ch_list_data.lkbh
  tb_xml[14] = [[</ns1:in12><ns1:in13>]]..ch_list_data.hpsztpzb
  tb_xml[15] = [[</ns1:in13><ns1:in14>]]..ch_list_data.jszb
  tb_xml[16] = [[</ns1:in14><ns1:in15>]]..ch_list_data.gfile1
  tb_xml[17] = [[</ns1:in15><ns1:in16>]]..ch_list_data.gfile2
  tb_xml[18] = [[</ns1:in16><ns1:in17 xsi:nil="true" />]]
  tb_xml[19] = [[</ns1:SetPassCarInfo_withImg>
          </soap:Body>
          </soap:Envelope>]]
  local ws_xml = table.concat(tb_xml)
  return ws_xml
end



local function check_data(hikid,server_ip,server_port,db_data)

  return true
end



local function flow_count(typ)     --计算发送次数
  local today = ngx.today()
  local now_date = string.sub(today,-2)
  if typ == "success" then
    local incr_data = {}
    local date_sendsuccessnum_key = "date_send_success_num_" .. now_date --一天发送成功的总次�?
    incr_data[date_sendsuccessnum_key] = 1
    vss_method.incr_data(incr_data)
  elseif typ == "failed" then
    local incr_data = {}
    local date_sendfailednum_key = "date_send_failed_num_" .. now_date --一天发送失败的总次�?
    incr_data[date_sendfailednum_key] = 1
    vss_method.incr_data(incr_data)
  elseif typ == "all" then
    local incr_data = {}
    local date_sendfailednum_key = "date_send_num_" .. now_date --一天发送的总次�?
    incr_data[date_sendfailednum_key] = 1
    vss_method.incr_data(incr_data)
  end
  return "ok",nil
end


----                       当天发送的总次�?date_send_num_)
local function flow_count1(workflow_id,byte)     --专门计算后置客户端发送的总次�?每秒)、当天发送的总流�?date_send_data_)、后置客户端总流�?每秒)、后置所有客户端发送的流量(hsdata)、后置所有客户端发送次�?hsnum)
  --local now_date  = os.date("%d")     --取当天日�?
  local today = ngx.today()
  local now_date = string.sub(today,-2)
  local nowtime   = ngx.time()
  local next_time = nowtime+1
  nowtime = tostring(nowtime)
  nowtime = str_sub(nowtime,-2) -- 取当前时间最�?�?
  next_time = tostring(next_time)
  next_time = str_sub(next_time,-2) --取下一秒时间后2�?
  local incr_data = {}
  --local del_data = {}
  local now_allnum_key = workflow_id .. "_reqnum_" .. nowtime    --后置客户端每秒发送总次�?
  local next_allnum_key = workflow_id .. "_reqnum_" .. next_time      --下一�?
  local now_allkb_key  = workflow_id .. "_datanum_" .. nowtime     --后置客户端每秒发送总流�?
  local next_allkb_key  = workflow_id .. "_datanum_" .. next_time   --下一�?
  local now_allhsnum_key  = "hsnum_" .. nowtime        --后置所有客户端发送总次�?
  local next_allhsnum_key  = "hsnum_" .. next_time         --下一�?
  local now_allhskb_key  = "hsdata_" .. nowtime  --后置所有客户端发送总流�?
  local next_allhskb_key  = "hsdata_" .. next_time         --下一�?
  local date_senddata_key  = "date_send_data_" .. now_date                 --后置客户端当天发送的总流�?
  local date_sendnum_key  = "date_send_num_" .. now_date    --后置客户端当天发送的总次�?
  incr_data[now_allnum_key] = 1            --当前一�?
  incr_data[now_allkb_key]  = math_floor(byte/1024)
  incr_data[date_senddata_key]  = math_floor(byte/1024)
  incr_data[now_allhsnum_key] = 1
  incr_data[now_allhskb_key] = math_floor(byte/1024)
  incr_data[date_sendnum_key] = 1
  local res,err = vss_method.incr_data(incr_data)   --计算每秒发送失败的次数
  if not res then
    utils.gcs_log("error","ws_send,incr_data is error,err:"..err)
  end
  --[[
  tb_insert(del_data,next_allnum_key)
  tb_insert(del_data,next_allkb_key)
  tb_insert(del_data,next_allhsnum_key)
  tb_insert(del_data,next_allhskb_key)
  local res,err = vss_method.del_data(del_data)     --删除下一秒发送失败的次数
  --]]
  return "ok",nil
end





local function flow_count2()     ---专门计算当天发送成功的总次�?
  --local now_date  = os.date("%d")     --取当天日�?
  local today = ngx.today()
  local now_date = string.sub(today,-2)
  local incr_data = {}
  local date_sendsuccessnum_key = "date_send_success_num_" .. now_date --一天发送成功的总次�?
  incr_data[date_sendsuccessnum_key] = 1
  local res,err = vss_method.incr_data(incr_data)
  if not res then
    utils.gcs_log("error","incr_data(success) is error,err:"..err)
  end
  return "ok",nil
end




--send_queue_num:一次发送的个数  qz_num:优先队列的权重数
--return code,tb_id_qname:{{id="",q_name=""}}


function get_tb_id_qname(send_queue_num,qz_num,cjson_queue,p_pop_lr)
  local tb_queue = cjson.decode(cjson_queue)
  local tb_id_qname = {}                 --队列名和id是唯一�?
  local i =  0                           --判断 线程�?
  local qz = 0                           --判断 权重�?
  while true do
    if tonumber(i) >= tonumber(send_queue_num) then break end
    if qz <=tonumber(qz_num) then
      for _,v in pairs(tb_queue) do
        if v.type == 'y' then
          local list_name = v.name  --取到name
          --utils.gcs_log("debug","vss_method pop start")
          local id,err = vss_method.pop(p_pop_lr,list_name) --返回队列里的头id
          --utils.gcs_log("debug","vss_method pop end")
          if not id then
            --list_pop() id为nil 可能服务器或程序问题
            --return nil,err,1701                                            --待写 错误�?
            utils.gcs_log("error","send,(queue)get id is err,err:" .. cjson.encode(err))
          elseif tonumber(id) ~= 0 then
            local tb_tmp = {}
            tb_tmp.id     = id
            tb_tmp.q_name = list_name
            tb_insert(tb_id_qname,tb_tmp)
            i = i+1
          end
        end
      end
      qz = qz +1
    else
      i = i+1
      for _,v in pairs(tb_queue) do
        if v.type == 'c' then
          local list_name = v.name  --取到name
          --utils.gcs_log("debug","vss_method pop start")
          local id,err = vss_method.pop(p_pop_lr,list_name) --返回队列里的头id
          --utils.gcs_log("debug","vss_method pop end")
          if not id then
            --list_pop() id为nil 可能服务器或程序问题
            --return nil,err,1701
            utils.gcs_log("error","send,(queue)get id is err,err:" .. cjson.encode(err))
          elseif tonumber(id) ~= 0 then
            local tb_tmp = {}
            tb_tmp.id     = id
            tb_tmp.q_name = list_name
            tb_insert(tb_id_qname,tb_tmp)
            i = i +1
          end
        end
      end
    end
  end
  for j=1,send_queue_num - #tb_id_qname do
    for _,v in pairs(tb_queue) do
      if v.type == 'l' then
        local list_name = v.name  --取到name
        local id,err = vss_method.pop(p_pop_lr,list_name) --返回队列里的头id
        if not id then
          --list_pop() id为nil 可能服务器或程序问题
          -- return nil,err,1701
          utils.gcs_log("error","send,(queue)get id is err,err:" .. cjson.encode(err))
        elseif tonumber(id) ~= 0 then
          local tb_tmp = {}
          tb_tmp.id     = id
          tb_tmp.q_name = list_name
          tb_insert(tb_id_qname,tb_tmp)
        end
      end
    end
  end
  return tb_id_qname,nil,nil
end

--单线程数
function send_tb_single(tb_id_qname)
  --取数据发�?
  local tb_send_id_qname = {}

  for i,v in pairs(tb_id_qname) do

    local res,err = vss_method.get_data(tb_id_qname[i].id)   --通过id 取到cjson res为cjson
    if not res then                                 --(一定能取到res)�?不到res code记为-2  重新插入队列继续�?
      utils.gcs_log("error","ws_send,get_data is error,code = 5,vssid" .. tb_id_qname[i].id..",err:"..cjson.encode(err))
      local tb_tmpe = {}
      tb_tmpe.vssid = tb_id_qname[i].id
      tb_tmpe.code  = -2
      tb_tmpe.q_name = tb_id_qname[i].q_name
      tb_insert(tb_send_id_qname,tb_tmpe)                                                                  --取不到要发送的数据 code 记为5 用于保存数据�?删除数据
    else
      local cjson_list_data = res[tb_id_qname[i].id]      --cjson_list_data == '' 则表�?数据库内无此key
      if cjson_list_data ~= "" then
          local tb_list_data = cjson.decode(cjson_list_data)
		  local a,j=string.find(tb_list_data.filename1,"Plate")
		    if a then 
			    local tb_tmpe = {}
				tb_tmpe.vssid = tb_id_qname[i].id
				tb_tmpe.code   = 0
				tb_tmpe.q_name = tb_id_qname[i].q_name
				tb_insert(tb_send_id_qname,tb_tmpe)
		    else 
			  local res,err = check_data(nil)                                                          --失败code记为-1
			  if not res then
		
				utils.gcs_log("error","ws_send,code = -5,vssid:"..tb_id_qname[i].id..",hikid:"..tb_list_data.hikid ..",send failed,hikid:"..tb_list_data.hikid)
			  else
				local ch_list_data,err = change_data(tb_list_data)
				if not ch_list_data then
				  local tb_tmpe = {}
				  tb_tmpe.vssid = tb_id_qname[i].id
				  tb_tmpe.code   = -2
				  tb_tmpe.q_name = tb_id_qname[i].q_name
				  tb_insert(tb_send_id_qname,tb_tmpe)
				  utils.gcs_log("error","ws_send code=-2 数据转换格式出错,"..err)
				else
				  local body = load_ws_xml(ch_list_data)
				  --utils.gcs_log("debug","send body:"..body)
				  flow_count("all")
				  
				  --utils.gcs_log("debug","send body:"..body)
				  
				  
				  -----------发送之前随机选择数据发送
				  local rt = StringSplit(tb_list_data.server_ip,",")       
				  local ran = math.random(1,#rt)
				  local server_ip = rt[ran]
				  utils.gcs_log("debug","发送ip:"..server_ip)
				  local res,err = webservice(server_ip,8090,body)
				 
				  if not res then
					flow_count("failed")
					local tb_tmpe = {}                                             --code记为4 插入队列重发
					tb_tmpe.vssid = tb_id_qname[i].id
					tb_tmpe.code   = -2
					tb_tmpe.q_name = tb_id_qname[i].q_name
					tb_insert(tb_send_id_qname,tb_tmpe)
					utils.gcs_log("error","ws_send code=-2 not response,ip:"..server_ip)
				  else
					if not res.body then
					  flow_count("failed")
					  local tb_tmpe = {}                                             --code记为-2 插入队列重发  用于保存数据�?
					  tb_tmpe.vssid = tb_id_qname[i].id
					  tb_tmpe.code  = -2
					  tb_tmpe.q_name = tb_id_qname[i].q_name
					  tb_insert(tb_send_id_qname,tb_tmpe)
					  utils.gcs_log("error","ws_send code=-2 not response body")                              --计算发送失败次�?
					else
					  local code,message,guid,err1 = check_body(res.body)
					  if tonumber(code) == 0 then
						flow_count("success")
						utils.gcs_log("info","ws_send code = 0,message:"..cjson.encode(message))
						local tb_tmpe = {}
						tb_tmpe.code = 0
						tb_tmpe.vssid = tb_id_qname[i].id
						tb_tmpe.q_name = tb_id_qname[i].q_name
		
						tb_insert(tb_send_id_qname,tb_tmpe)           --code=0 表示发送成�?保存数据�?删除数据 删除storage
						--local res,err = flow_count2()
					  elseif tonumber(code) == -1 then      --code=-1 表示发送失�?保存数据�?删除数据 删除storage 计算请求�?
						local tb_tmpe = {}
						tb_tmpe.code = -1
						tb_tmpe.vssid= tb_id_qname[i].id
						tb_tmpe.hikid= tb_list_data.hikid
						tb_tmpe.q_name = tb_id_qname[i].q_name
						tb_tmpe.hz_storage = tb_list_data.hz_storage
						tb_tmpe.gfile1 = tb_list_data.gfile1              --传gfile1,gfile2 用于删除storage
						if tb_list_data.gfile2 then
						  tb_tmpe.gfile2 = tb_list_data.gfile2
						end
						tb_insert(tb_send_id_qname,tb_tmpe)
		
						local workflow_id = config_table:get("h_"..tb_list_data.host)
						local res,err = flow_count(workflow_id)                               --计算发送失败次�?                                          --code=-2 表示重发 计算请求�?
					  elseif tonumber(code) == -2 then
						flow_count("failed")
						utils.gcs_log("error","ws_send code = -2,message:"..cjson.encode(message))
						local tb_tmpe = {}
						tb_tmpe.code = -2
						tb_tmpe.vssid = tb_id_qname[i].id
						tb_tmpe.q_name = tb_id_qname[i].q_name
						tb_insert(tb_send_id_qname,tb_tmpe)
					  elseif tonumber(code) == -3 then
					  --code=-3(表示对方队列已满 sleep 1秒 插入队列重发)
		
					  else                                               --意外情况 code=6 用于重发
					  --code=6 表示重发
					  end
					end
				  end
				end
			end	
          end
      end
    end
  end
  return tb_send_id_qname,nil,nil
    --return code,tb_send_id_qname,err
end


---删除storage
function del_storage(storage_res,tb_value,storage_tb)
  local arg = tb_value
  local st = storage:new()
  st:set_timeout(arg.timeout)
  local ok, err = st:connect(storage_res)
  if not ok then
    return nil,err,1100                             --错误码待定义
  else
    -- utils.gcs_log("debug","456"..storage_tb.gfile1)
    local res,err = st:delete_file1(storage_tb.gfile1)
    if not res then
      return nil,err,1008
    end
    -- utils.gcs_log("debug",res)
    if storage_tb.gfile2 ~= "" then
      local res,err = st:delete_file1(storage_tb.gfile2)
      if not res then
        return nil,err,1008
      end
    end
  end
  --关闭storage
  local ok, err = st:set_keepalive(arg.keep_timeout,arg.keep_count)
  return "del storage is ok",nil,nil
end


---专门计算每天删除后置storage的次�?

function del_hz_storage_num()
  --local now_date  = os.date("%d")     --取当天日�?
  local today = ngx.today()
  local now_date = string.sub(today,-2)
  local date_del_hz_storage_num = "date_del_hz_storage_num_"..now_date
  local incr_data = {}
  incr_data[date_del_hz_storage_num] = 1
  local res,err = vss_method.incr_data(incr_data)
  if not res then
    utils.gcs_log("error","incr_data(del_hz_storage) is error,err:"..err)
  end
  return "ok",err
end

function get_l_listname()
  return "l_list"   --历史队列名称
end

function record_tb(tb_send_id_qname)   --记录结果

--return code,err
end
